<template>
	<div class="joint-scheduling">
		<!-- 调度说明 -->
		<el-card style="margin-bottom:18px;">
			<div style="font-weight:bold;">
				联合调度场景说明
			</div>
			<div style="margin-top:6px;">
				当前场景为<span style="color:#409EFF">多产线协同</span>+<span
					style="color:#67C23A">AGV资源共享</span>，生产订单自动分配到不同产线，AGV负责各产线物料、半成品搬运与协同任务。
			</div>
		</el-card>

		<!-- 协同调度表格 -->
		<el-card style="margin-bottom:18px;">
			<div style="font-weight:bold;margin-bottom:10px;">产线&AGV协同调度任务表</div>
			<el-table :data="taskData" border size="small">
				<el-table-column prop="orderNo" label="订单编号" width="120" />
				<el-table-column prop="product" label="成品名称" width="120" />
				<el-table-column prop="line" label="分配产线" width="110" />
				<el-table-column prop="agv" label="分配AGV" width="110" />
				<el-table-column prop="start" label="开始" width="110" />
				<el-table-column prop="end" label="结束" width="110" />
				<el-table-column prop="status" label="状态" width="90">
					<template #default="scope">
						<el-tag :type="scope.row.status === '已完成' ? 'success' : (scope.row.status === '运输中' ? 'warning' : 'info')">
							{{ scope.row.status }}
						</el-tag>
					</template>
				</el-table-column>
				<el-table-column prop="desc" label="协同说明" />
			</el-table>
		</el-card>

		<!-- 协同甘特图 -->
		<el-card>
			<div style="font-weight:bold;margin-bottom:10px;">多产线&AGV联合调度甘特图</div>
			<div ref="ganttRef" style="width:100%;min-width:720px;height:360px;"></div>
		</el-card>
	</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'

// 联合调度任务模拟数据
const taskData = [
	{ orderNo: 'ORD-1001', product: '头孢曲松钠注射液', line: '产线A', agv: 'AGV-01', start: '2024-06-11', end: '2024-06-13', status: '已完成', desc: 'AGV-01搬运原料' },
	{ orderNo: 'ORD-1002', product: '阿莫西林胶囊', line: '产线B', agv: 'AGV-02', start: '2024-06-12', end: '2024-06-15', status: '运输中', desc: 'AGV-02搬运半成品' },
	{ orderNo: 'ORD-1003', product: '葡萄糖注射液', line: '产线A', agv: 'AGV-01', start: '2024-06-13', end: '2024-06-15', status: '待运输', desc: '等待产线调度' },
	{ orderNo: 'ORD-1004', product: '布洛芬缓释胶囊', line: '产线C', agv: 'AGV-03', start: '2024-06-14', end: '2024-06-16', status: '待运输', desc: 'AGV-03将成品送至仓库' }
]

// 甘特图数据结构（以产线+AGV为纵向分组）
const ganttRows = [
	{ name: '产线A', color: '#409EFF' },
	{ name: '产线B', color: '#67C23A' },
	{ name: '产线C', color: '#E6A23C' },
	{ name: 'AGV-01', color: '#909399' },
	{ name: 'AGV-02', color: '#F56C6C' },
	{ name: 'AGV-03', color: '#36CFC9' }
]
// 任务甘特条
const ganttBars = [
	{ group: '产线A', label: '头孢曲松分装', start: '2024-06-11', end: '2024-06-13', color: '#409EFF' },
	{ group: '产线A', label: '葡萄糖注射', start: '2024-06-13', end: '2024-06-15', color: '#409EFF' },
	{ group: '产线B', label: '阿莫西林包装', start: '2024-06-12', end: '2024-06-15', color: '#67C23A' },
	{ group: '产线C', label: '布洛芬包装', start: '2024-06-14', end: '2024-06-16', color: '#E6A23C' },
	{ group: 'AGV-01', label: '头孢原料搬运', start: '2024-06-11', end: '2024-06-13', color: '#909399' },
	{ group: 'AGV-01', label: '葡萄糖搬运', start: '2024-06-13', end: '2024-06-15', color: '#909399' },
	{ group: 'AGV-02', label: '阿莫西林搬运', start: '2024-06-12', end: '2024-06-15', color: '#F56C6C' },
	{ group: 'AGV-03', label: '布洛芬转运', start: '2024-06-14', end: '2024-06-16', color: '#36CFC9' }
]

// 时间序列
function getDateRange(start, end) {
	const res = []
	let dt = new Date(start)
	const ed = new Date(end)
	while (dt <= ed) {
		res.push(dt.toISOString().slice(0, 10))
		dt.setDate(dt.getDate() + 1)
	}
	return res
}
const xDates = getDateRange('2024-06-11', '2024-06-16')

// 渲染联合甘特图
const ganttRef = ref()
let chart
function renderGantt() {
	if (!chart && ganttRef.value) chart = echarts.init(ganttRef.value)
	if (!chart) return

	chart.setOption({
		tooltip: {
			formatter: params => {
				const bar = ganttBars[params.dataIndex]
				return `${bar.group}: ${bar.label}<br/>${bar.start} ~ ${bar.end}`
			}
		},
		grid: { left: 110, right: 20, top: 40, bottom: 36, containLabel: true },
		xAxis: {
			type: 'category',
			data: xDates,
			axisLabel: { rotate: 22 }
		},
		yAxis: {
			type: 'category',
			data: ganttRows.map(r => r.name),
			inverse: true
		},
		series: [{
			type: 'custom',
			renderItem: (params, api) => {
				const bar = ganttBars[params.dataIndex]
				const yIndex = ganttRows.findIndex(r => r.name === bar.group)
				const start = xDates.indexOf(bar.start)
				const end = xDates.indexOf(bar.end)
				const y = api.coord([0, yIndex])[1]
				const xStart = api.coord([start, yIndex])[0]
				const xEnd = api.coord([end + 1, yIndex])[0]
				const height = 16
				return {
					type: 'rect',
					shape: {
						x: xStart,
						y: y - height / 2,
						width: xEnd - xStart,
						height
					},
					style: api.style({
						fill: bar.color,
						stroke: '#fff'
					}),
					textContent: {
						type: 'text',
						style: {
							text: bar.label,
							x: (xStart + xEnd) / 2,
							y: y + 1,
							font: 'bold 12px sans-serif',
							fill: '#fff',
							textAlign: 'center',
							verticalAlign: 'middle'
						}
					},
					textConfig: {
						position: 'inside'
					}
				}
			},
			encode: { x: [0, 1], y: 0 },
			data: ganttBars.map((b, i) => i)
		}]
	})
}

onMounted(() => {
	setTimeout(renderGantt, 20)
})
</script>

<style scoped>
.joint-scheduling {
	padding: 16px;
}
</style>
  
